package main

import (
	"fmt"
	"sort"
)

//切片的常用相关操作整理

//复制

func CopySlice1(a []int) []int {
	b := make([]int, len(a)) //一次性将内存申请到位
	copy(b, a)               //利用内置的 copy 函数
	return b
}

func CopySlice2(a []int) []int {
	b := append([]int(nil), a...)
	fmt.Println(b)
	b = append(a[:0:0], a...)
	return b
	//这两种方法通常比使用copy函数复制的方法要慢一些，但是如果在复制之后有更多的元素要添加到b中，那么它们的效率会更高。
}

//剪切

func CutSlice(a []int, i, j int) []int {
	a = append(a[:i], a[j:]...) //	去掉[i,j)之间的部分
	return a
}

// 删除

func DeleteSlice(a []int, i int) []int {
	a = append(a[:i], a[i+1:]...) //删除第 i+1 个位置
	return a
	// a = a[:i + copy(a[i:],a[i+1:])] 不是很好理解

	//如果只需要删除掉索引为i的元素，无需保留切片元素原有的顺序，那么还可以使用下面这种简单的方式进行删除
	//a[i] = a[len(a)-1]  // 将最后一个元素移到索引i处
	//a = a[:len(a)-1]    // 截掉最后一个元素
}

//剪切或删除操作可能引起的内存泄露！！！
//需要特别注意的是。如果切片a中的元素是一个指针类型或包含指针字段的结构体类型（需要被垃圾回收），
//上面剪切和删除的示例代码会存在一个潜在的内存泄漏问题：一些具有值的元素仍被切片a引用，
//因此无法被垃圾回收机制回收掉。下面的代码可以解决这个问题。

func SafeCutSlice(a []int, i, j int) []int {
	copy(a[i:], a[j:])
	for k, n := len(a)-j+i, len(a); k < n; k++ {
		a[k] = 0 // 或类型T的零值
	}
	a = a[:len(a)-j+i]

	return a
}

func SafeDeleteSlice(a []int, i int) []int {
	copy(a[i:], a[i+1:])
	a[len(a)-1] = 0 // 或类型T的零值
	a = a[:len(a)-1]
	return a
}

// SafeDeleteSliceWithoutOrder 删除但不保留原有顺序
func SafeDeleteSliceWithoutOrder(a []int, i int) []int {
	a[i] = a[len(a)-1]
	a[len(a)-1] = 0
	a = a[:len(a)-1]
	return a
}

// 滑动窗口 将切片input生成size大小的滑动窗口

func slidingWindow(size int, input []int) [][]int {
	if len(input) <= size {
		return [][]int{input}
	}

	//以所需的精确大小分配切片
	r := make([][]int, 0, len(input)-size+1)

	//for i, j := 0, size; j <= len(input); i, j = i+1, j+1 {
	//	r = append(r, input[i:j])
	//}

	for i := 0; i < len(input)-size+1; i++ {
		r = append(r, input[i:i+size])
	}

	return r
}

// DeleteDuplicateItem 就地删除重复元素（元素可比较）
func DeleteDuplicateItem(a []int) []int {
	sort.Ints(a)
	j := 0
	for i := 1; i < len(a); i++ {
		if a[j] == a[i] {
			continue
		}
		j++

		a[j] = a[i]
	}

	result := a[:j+1]
	return result
}

// moveToFront 把needle移动或添加到haystack的前面 元素存在就移到最前面，不存在则放在前面
func moveToFront(needle string, haystack []string) []string {
	if len(haystack) != 0 && haystack[0] == needle {
		return haystack
	}
	prev := needle
	for i, elem := range haystack {
		switch {
		case i == 0:
			haystack[0] = needle
			prev = elem
		case elem == needle:
			haystack[i] = prev
			return haystack
		default:
			haystack[i] = prev
			prev = elem
		}
	}
	return append(haystack, prev)
}

func main() {
	//a := []int{1, 2, 3, 4, 5}
	//res := slidingWindow(3, a)
	//fmt.Println(res)

	haystack := []string{"a", "b", "c", "d", "e"} // [a b c d e]
	haystack = moveToFront("c", haystack)         // [c a b d e]
	haystack = moveToFront("f", haystack)         // [f c a b d e]
}
